package entity_model;

import entity_model.data_types.DataType;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import utils.Base;
import utils.titles.Title;

import java.util.LinkedHashMap;
import java.util.Map;

import static entity_model.Relationship.Role.Cardinality.MANY;
import static entity_model.Relationship.Role.Cardinality.ONE;
import static utils.titles.Title.CAPITAL_CASE;

/**
* Created by nuno-rafael-figueiredo on 08-05-2014.
*/
public class Entity extends Base {
    private transient final EntityModel model;
    private transient final ObservableList<Attribute> attributes = FXCollections.observableArrayList();
    private transient final ObservableList<Relationship.Related> relateds = FXCollections.observableArrayList();
    private transient final ObservableList<Operation> operations = FXCollections.observableArrayList();

    public transient final Map<Relationship.Direction, ObservableList<Relationship.Related>> relationshipMap = new LinkedHashMap<>();

    {
        for(Relationship.Direction type : entity_model.Relationship.Direction.values())
            relationshipMap.put(type, FXCollections.observableArrayList());
    }

    transient private Entity baseEntity;
    private boolean anAbstract;

    public Entity(EntityModel model, Title title) {
        super(CAPITAL_CASE, title);
        this.model = model;
    }

    public Entity(EntityModel model, String capitalized) {
        this(model, Title.fromCapitalized(capitalized));
    }

    public void setBaseEntity(Entity baseEntity) {
        this.baseEntity = baseEntity;
        baseEntity.setAbstract();
    }

    public Attribute createAttribute(DataType dataType, Title title) {
        final Attribute attribute = new Attribute(dataType, title);
        getAttributes().add(attribute);
        return attribute;
    }

    public void add(Relationship.Related related) {
        getRelateds().add(related);
        relationshipMap.get(related.getDirection()).add(related);
    }

    public String getBaseName(){
        return baseEntity == null ? null : baseEntity.getName();
    }

    public Entity getBaseEntity() {
        return baseEntity;
    }

    public boolean isAbstract() {
        return anAbstract;
    }

    public void setAbstract() {
        this.anAbstract = true;
    }

    public ObservableList<Attribute> getAttributes() {
        return attributes;
    }

    public ObservableList<Relationship.Related> getRelateds() {
        return relateds;
    }

    public ObservableList<Operation> getOperations() {
        return operations;
    }

    public void hasMany(Entity entity) {
        model.createRelationship(MANY, entity, this);
    }

    public void hasMany(Entity other, Title title) {
        model.createRelationship(MANY, other, this, title);
    }

    public void hasOne(Entity entity) {
        model.createRelationship(ONE, entity, this);
    }

    public void hasOne(Entity entity, Title title) {
        model.createRelationship(ONE, entity, this, title);
    }

    public EntityModel getModel() {
        return model;
    }
}
